package rlog

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"

	"gitee.com/terender/sfw/utils"
)

// RotateLogger 每天向前滚动的日志写入器
type RotateLogger struct {
	name           string             // 日志名，日志文件名前缀
	file           *os.File           // 当前日志写入文件
	latestFileName string             // 当前日志文件的名字
	logger         *log.Logger        // 日志写入器
	message        chan []interface{} // 待写入的日志队列
	outputToStd    int32              // 日志内容是否写入stdout
	closed         int32
	quitChan       chan bool
}

// // NewRotateLogger 创建一个新的RotateLogger 并且加入缓存池
// func NewRotateLogger(name string) *RotateLogger {
// 	logManager.Lock()
// 	defer logManager.Unlock()
// 	if rl, ok := logManager.loggers[name]; ok {
// 		return rl
// 	}
// 	rl := &RotateLogger{
// 		name:    name,
// 		message: make(chan []interface{}, 100),
// 	}
// 	logManager.loggers[name] = rl
// 	go rl.printProc()
// 	log.Printf(`日志[%v]创建完毕`, name)
// 	return rl
// }

// touch 确保一个RotateLogger 内部的logger被创建出来并且目标是正确的文件
func (rl *RotateLogger) touch() error {
	var err error
	tmpfilename := fmt.Sprintf(`%s/logs/%s/%s_%s.log`, utils.ProjectPath(), moduleName, rl.name, time.Now().Format("2006_01_02"))

	if tmpfilename != rl.latestFileName {
		if rl.file != nil {
			rl.file.Close()
		}
		rl.latestFileName = tmpfilename
		utils.CreatePath(filepath.Dir(rl.latestFileName))
		rl.file, err = os.OpenFile(rl.latestFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
		if err != nil {
			Errorf(`创建新日志文件[%v]失败: %v`, tmpfilename, err)
			return err
		}
	}
	rl.logger = log.New(rl.file, ``, log.LstdFlags|log.Lmicroseconds)
	return nil
}

// 开启或者关闭一个 RotateLogger 的日志内容是否写入stdout功能
func (rl *RotateLogger) OutputToSTD(on bool) {
	if on {
		atomic.StoreInt32(&rl.outputToStd, 1)
	} else {
		atomic.StoreInt32(&rl.outputToStd, 0)
	}
}

// printProc 日志写入线程
// 日志的写入采用了异步方案，保证逻辑线程的性能不受影响
func (rl *RotateLogger) printProc() {
	defer func() {
		if err := recover(); err != nil {
			Errorf(fmt.Sprintf("panic recover:panic info:%v", err))
			Rawf(string(debug.Stack()))
			go rl.printProc()
		}
	}()
	for msg := range rl.message {
		if err := rl.touch(); err == nil {
			rl.logger.Print(msg...)
		}
		//log.SetPrefix(`[` + rl.Name + `]`)
		//log.Print(msg...)
	}
	if rl.file != nil {
		rl.file.Close()
	}
	rl.quitChan <- true
}

func generatePrifex(level string) string {
	pc, _, l, _ := runtime.Caller(3)
	return fmt.Sprintf("[%s]%s(%d) _goid[%d]: ", level, runtime.FuncForPC(pc).Name(), l, _goid())
}

// LogRaw 输出日志
func (rl *RotateLogger) LogRaw(v ...interface{}) {
	if atomic.LoadInt32(&rl.closed) == 0 {
		rl.message <- v
	}
	if atomic.LoadInt32(&rl.outputToStd) == 1 {
		log.Print(v...)
	}
}

// LogLevel 打印指定等级前缀的日志，并且加入调用函数以及运行的Goroutine ID信息
func (rl *RotateLogger) LogLevel(level string, v ...interface{}) {
	if level == `` {
		level = `info`
	}
	v = append([]interface{}{generatePrifex(level)}, v...)
	rl.LogRaw(v...)
}

// Log 按照默认等级(info)输出日志
func (rl *RotateLogger) Log(v ...interface{}) { rl.LogLevel(``, v...) }

// Close 关闭一个RotateLogger
func (rl *RotateLogger) Close(quitChan chan bool) {
	atomic.StoreInt32(&rl.closed, 1)
	rl.quitChan = quitChan
	close(rl.message)
}

// 日志写入器池，管理不同日志文件名的写入器
var logManager = struct {
	sync.RWMutex
	loggers map[string]*RotateLogger
}{
	loggers: make(map[string]*RotateLogger),
}

// // FindLogger 根据 name 查找日志写入器
// func FindLogger(name string) (*RotateLogger, bool) {
// 	logManager.RLock()
// 	defer logManager.RUnlock()
// 	info, ok := logManager.loggers[name]
// 	if !ok {
// 		return nil, false
// 	}
// 	return info, true
// }
